/*
 * Copyright (c) 2010-2011 Plugger Antonio Begue Ponce. All Rights Reserved.
 *
 * This file is part of Plugger Framework.
 *
 *  Plugger Framework is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License version 3 as published by
 *  the Free Software Foundation.
 *
 *  Plugger Framework is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with Plugger Framework.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.plugger.data;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;

/**
 * A helper class for low level jdbc database access.
 *
 * @author Antonio Begue
 * @version $Revision: 1.0 $
 *
 * @see     DatabaseType
 * @see     ConnectionStringHelper
 * @see     ConnectionString
 * @see     MapperParameters
 * @see     DataConfiguration
 */
public class DalManager {
    private Connection connection = null;
    private ConnectionString connectionString = null;
    private Statement statement = null;

    /**
     * Public DalManager constructor.
     */
    public DalManager() {
        connectionString = DataConfiguration.getConnectionString();
    }

    /**
     * Build a connection using the configured connection string.
     *
     * @return java.sql.Connection
     * @throws Exception
     */
    public Connection getConnection() throws Exception {
        try {
            if (connection == null) {
                Class.forName(connectionString.getProvider());
                connection = DriverManager.getConnection(connectionString.toString());
            }
            return connection;
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * Return the current statement object to send statement to the database.
     *
     * @return java.sql.Statement
     * @throws Exception
     */
    public Statement getStatement() throws Exception {
        if (statement == null) {
            statement = getConnection().createStatement();
        }
        return statement;
    }

    /**
     * The PreparedStatement is used to send parameterized statement to the database.
     *
     * @param sql The sql statement to send.
     * @return java.sql.PreparedStatement
     * @throws Exception
     */
    public PreparedStatement getPreparedStatement(String sql) throws Exception {
        return getConnection().prepareStatement(sql);
    }

    /**
     * Execute the sql and return a ResultSet.
     *
     * @param sql statement to send.
     * @return java.sql.ResultSet
     * @throws Exception
     */
    public ResultSet executeQuery(String sql) throws Exception {
        return getStatement().executeQuery(sql);
    }

    /**
     * Execute a stored procedure.
     *
     * @param procedureName the name and parameters of the stored procedure.
     * @return java.sql.ResultSet
     * @throws Exception
     */
    public ResultSet executeProcedure(String procedureName) throws Exception {
        Connection conn = getConnection();
        CallableStatement cs = conn.prepareCall(procedureName);
        return cs.executeQuery("{call " + procedureName + "}");
    }

    /**
     * Execute the given statement, witch may be an INSERT, UPDATE or DELETE statement
     * @param sql The statement to be send.
     * @return an integer representing the number of rows affected or 0 if no return.
     * @throws Exception
     */
    public int executeUpdate(String sql) throws Exception {
        return getStatement().executeUpdate(sql);
    }

    /**
     * Closes the connection and the current statement.
     *
     * @throws Exception
     */
    public void close() throws Exception {
        if (statement != null) {
            statement.close();
        }
        if (connection != null) {
            connection.close();
        }
    }

    /**
     * Initialize a database transaction.
     *
     * @throws Exception
     */
    public void beginTransaction() throws Exception {
        getConnection().setAutoCommit(false);
    }

    /**
     * Commit a database transaction.
     *
     * @throws Exception
     */
    public void commitTransaction() throws Exception {
        getConnection().commit();
        getConnection().setAutoCommit(true);
    }

    /**
     * Rollback a database transaction.
     *
     * @throws Exception
     */
    public void rollbackTransaction() throws Exception {
        getConnection().rollback();
        getConnection().setAutoCommit(true);
    }
}
